/*********************************************************************/
/**************** get line size in width 480 threads *****************/
__global__ void getLineSizeWidthCUDA(int width, unsigned char *g_imageArray)
{
	// get current position in array
	int tid = threadIdx.x;
	int bid = blockIdx.x;
	int bdim = blockDim.x;
	int currentPosition = width * ((bid * bdim) + tid);
	int endPosition = currentPosition + width;

	int firstPixelPosition, pixelMidPoint, offset;

	while (currentPosition < endPosition)
	{
		if(g_imageArray[currentPosition] == 1)
		{
			offset = 1;
			firstPixelPosition = currentPosition;
			while(g_imageArray[firstPixelPosition + offset] != 0)
			{
				offset++;
			}
			currentPosition = firstPixelPosition + offset /*- 1*/;
			pixelMidPoint = (firstPixelPosition + currentPosition) / 2;
			g_imageArray[pixelMidPoint] = 2;
		}
		currentPosition++;
	}
}
/**************** get line size in width 480 threads *****************/
/*********************************************************************/


/*********************************************************************/
/**************** get line size in height 640 threads ****************/
__global__ void getLineSizeHeightCUDA(int height, int width, unsigned char *g_imageArray)
{
	// get current position in array
	int tid = threadIdx.x;
	int bid = blockIdx.x;
	int bdim = blockDim.x;
	int currentPosition = (bid * bdim) + tid;
	int endPosition = currentPosition + (width * (height - 1));

	int firstPixelPosition, secondPixelFound, pixelMidPoint, offset;

	while (currentPosition < endPosition)
	{
		if(g_imageArray[currentPosition] != 0)
		{
			secondPixelFound = 0;
			offset = 1;
			firstPixelPosition = currentPosition;
			while(secondPixelFound != 1)
			{
				if (g_imageArray[currentPosition + (offset * width)] != 0)
				{
					offset++;
				}
				else
				{
					secondPixelFound = 1;
				}
			}
			pixelMidPoint = firstPixelPosition + ((offset / 2) * width);
			if(g_imageArray[pixelMidPoint] == 2)
			{
				g_imageArray[pixelMidPoint] = 4;
			}
			else
			{
				g_imageArray[pixelMidPoint] = 3;
			}
			currentPosition = currentPosition + (offset * width);
		}
		else
		{
			currentPosition = currentPosition + width;
		}
	}
}
/**************** get line size in height 640 threads ****************/
/*********************************************************************/

///*********************************************************************/
///*************************** draw a circle ***************************/
//void drawCircle(int height, int width, int startX, int startY, int radius, unsigned char *anArray, unsigned char circleColour)
//{
//    int f = 1 - radius;
//    int ddF_x = 1;
//    int ddF_y = -2 * radius;
//    int x = 0;
//    int y = radius;
//
//	anArray[(startX * width) + (startY + radius)] = circleColour;
//	anArray[(startX * width) + (startY - radius)] = circleColour;
//	anArray[((startX + radius) * width) + startY] = circleColour;
//	anArray[((startX - radius) * width) + startY] = circleColour;
// 
//    while(x < y)
//    {
//      if(f >= 0) 
//      {
//        y--;
//        ddF_y += 2;
//        f += ddF_y;
//      }
//      x++;
//      ddF_x += 2;
//      f += ddF_x; 
//
//	  anArray[((startX + x) * width) + (startY + y)] = circleColour;
//	  anArray[((startX - x) * width) + (startY + y)] = circleColour;
//	  anArray[((startX + x) * width) + (startY - y)] = circleColour;
//	  anArray[((startX - x) * width) + (startY - y)] = circleColour;
//	  anArray[((startX + y) * width) + (startY + x)] = circleColour;
//	  anArray[((startX - y) * width) + (startY + x)] = circleColour;
//	  anArray[((startX + y) * width) + (startY - x)] = circleColour;
//	  anArray[((startX - y) * width) + (startY - x)] = circleColour;
//    }
//}
///*************************** draw a circle ***************************/
///*********************************************************************/

/*********************************************************************/
/*** Test to see if charValue hits a 0 indicating blob size is max ***/
__global__ void testMaxDilationCUDA(int width, int charValue, unsigned char *g_imageArray, int *g_maxDilation)
{
	int idx = blockIdx.x*blockDim.x + threadIdx.x;

	if(g_imageArray[idx] == charValue && *g_maxDilation == 0)
    {
		if (g_imageArray[idx + 1] == 0 || g_imageArray[idx - 1] == 0 || g_imageArray[idx + width] == 0 || g_imageArray[idx - width] == 0)
		{
			while(*g_maxDilation == 0)
			{
				*g_maxDilation = 1;
			}
		}
	}
}
/*** Test to see if charValue hits a 0 indicating blob size is max ***/
/*********************************************************************/


// Get blob size for any blue intersection, means unsigned char value of 4
// find size using circle method
int getSizeOfBlobCUDA(int height, int width, unsigned char *h_imageArray)
{
	int i, j, charValue, radius, largestBlobSize;
	charValue = 5;
	largestBlobSize = 0;

	int* h_maxDilation = (int *)malloc(sizeof(int));
	int* d_maxDilation;
	CUDA_SAFE_CALL(cudaMalloc((void**)&d_maxDilation, sizeof(int)));
	unsigned char* e_imageArray;
	CUDA_SAFE_CALL(cudaMalloc((void**)&e_imageArray, sizeof(unsigned char) * height * width));

	// used to get the mid point in a horizontal line
	// iterate through array to find first pixel
	for (i = 1; i < height - 1; i++)
	{
		for (j = 1; j < width - 1; j++)
		{
			// Find blue pixel
			if (h_imageArray[(i * width) + j] == 1)
			{
				printf("i: %d - j: %d\n", i, j);
				*h_maxDilation = 0;
				CUDA_SAFE_CALL(cudaMemcpy(d_maxDilation, h_maxDilation, sizeof(int), cudaMemcpyHostToDevice));
				radius = 1;

				// Do dilation using a colour which is distinct, unsigned char value of 5
				// make value 4 to value 5 and dilate as much as necessary until 5 contacts a 0
				// repeat this until the unsigned charValue meets a black pixel
				printf("h_maxDilation: %d\n", *h_maxDilation);
				//while(*h_maxDilation != 1)
				while(*h_maxDilation == 0)
				{
					drawCircle(height, width, i, j, radius, h_imageArray, charValue);
					radius++;

					CUDA_SAFE_CALL(cudaMemcpy(e_imageArray, h_imageArray, sizeof(unsigned char) * MAX_DATA_SIZE, cudaMemcpyHostToDevice));
					
					testMaxDilationCUDA<<<3200, 96>>>(width, charValue, e_imageArray, d_maxDilation);

					CUDA_SAFE_CALL(cudaMemcpy(h_maxDilation, d_maxDilation, sizeof(int), cudaMemcpyDeviceToHost));
					printf("h_maxDilation after: %d\n", *h_maxDilation);
					printf("\n");
				}

				if ((radius-1) * 2 > largestBlobSize)
				{
					largestBlobSize = (radius-1) * 2;
				}
				//if (radius * 2 > largestBlobSize)
				//{
				//	printf("radius: %d\n", radius);
				//	largestBlobSize = radius * 2;
				//}
				charValue++;
			}
		}
	}

	
	printf("Largest blob in pixels is: %d \n", largestBlobSize);
	//printf("Largest blob I: %d \n", largestBlobI);
	//printf("Largest blob J: %d \n", 639 - largestBlobJ);

	free(h_maxDilation);
	CUDA_SAFE_CALL(cudaFree(d_maxDilation)); 
	CUDA_SAFE_CALL(cudaFree(e_imageArray)); 
	return largestBlobSize;
}